<!--
 * @Date: 2022-03-27 15:32:23
 * @LastEditors: sailornpg
 * @LastEditTime: 2022-03-28 19:02:11
 * @FilePath: \vue3Components\src\components\Form\MyForm.vue
 * @Description: something  
  
-->
<template>
  <el-form
    ref="form"
    v-if="model"
    :validate-on-rule-change="false"
    :model="model"
    :rules="rules"
    v-bind="$attrs"
  >
    <template v-for="(item, index) in options" :key="index">
      <el-form-item
        v-if="!item.children || !item.children!.length"
        :prop="item.prop"
        :label="item.label"
      >
        <component
          v-if="item.type !== 'upload' && item.type !== 'editor'"
          :placeholder="item.placeholder"
          v-bind="item.attrs"
          :is="`el-${item.type}`"
          v-model="model[item.prop!]"
        ></component>
        <el-upload
          v-if="item.type === 'upload'"
          v-bind="item.uploadAttrs"
          :on-preview="onPreview"
          :on-remove="onRemove"
          :on-success="onSuccess"
          :on-error="onError"
          :on-progress="onProgress"
          :on-change="onChange"
          :before-upload="beforeUpload"
          :before-remove="beforeRemove"
          :http-request="httpRequest"
          :on-exceed="onExceed"
        >
          <slot name="uploadArea"></slot>
          <template #tip>
            <slot name="uploadTip"></slot>
          </template>
        </el-upload>
        <div id="editor" v-if="item.type === 'editor'"></div>
      </el-form-item>
      <el-form-item
        v-if="item.children && item.children.length"
        :prop="item.prop"
        :label="item.label"
      >
        <component
          :placeholder="item.placeholder"
          v-bind="item.attrs"
          :is="`el-${item.type}`"
          v-model="model[item.prop!]"
        >
          <component
            v-for="(child, i) in item.children"
            :key="i"
            :is="`el-${child.type}`"
            :label="child.label"
            :value="child.value"
          ></component>
        </component>
      </el-form-item>
    </template>
    <el-form-item>
      <slot name="action" :form="form" :model="model"></slot>
    </el-form-item>
  </el-form>
</template>
 <script lang='ts' setup>
import { FormOptions, FormInstance } from './type/type'
import { PropType, onMounted, ref, watch, nextTick } from 'vue';
import cloneDeep from 'lodash/cloneDeep'
import E from 'wangeditor'
import { UploadFile, UploadFiles, UploadProgressEvent, UploadRawFile, UploadRequestOptions } from 'element-plus'
let model = ref<any>(null)
let rules = ref<any>(null)
let form = ref<FormInstance | null>(null)
let wangEditor = ref()
const emits = defineEmits(['on-preview', 'on-remove', 'on-success', 'on-error', 'on-progress', 'on-change', 'before-upload', 'before-remove', 'on-exceed'])
const props = defineProps({
  //表单配置项
  options: {
    type: Array as PropType<FormOptions[]>,
    required: true
  },
  //自定义上传方法
  httpRequest: {
    type: Object as PropType<UploadRequestOptions>,
  }
})
//表单验证
const formValidate = () => {
  return form.value!.validate
}
//获取表单数据
const getFormData = () => {
  return model.value
}
const initFrom = () => {
  if (props.options && props.options.length) {
    let m: any = {}
    let r: any = {}
    props.options.map((item) => {
      m[item.prop!] = item.value
      r[item.prop!] = item.rules
      if (item.type === 'editor') {
        //初始化富文本
        nextTick(() => {
          if (document.getElementById('editor')) {
            const editor = new E('#editor')
            //保存实例
            wangEditor.value = editor
            editor.config.placeholder = item.placeholder!
            editor.create()
            //富文本内容初始化，传入value
            editor.txt.html(item.value)
            //实时改变内容复制给model,提交时拿到最新的值
            editor.config.onchange = (val: string) => {
              model.value[item.prop!] = val
            }
          }
        })

      }
    })
    model.value = cloneDeep(m)
    rules.value = cloneDeep(r)
  }
}
const resetFields = () => {
  console.log(form.value);
  //重置element表单
  form.value!.resetFields()
  if (props.options && props.options.length) {
    let edit = props.options.find(item => item.type === 'editor')
    console.log(edit!.value);
    wangEditor.value.txt.html(edit!.value)
  }
}
const onPreview = (uploadFile: UploadFile) => {
  emits('on-preview', uploadFile)
}
const onRemove = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
  emits('on-remove', { uploadFile, uploadFiles })
}
const onSuccess = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
  let uploadRes = props.options.find(item => {
    return item.type === 'upload'
  })
  model.value[uploadRes!.prop!] = { response, uploadFile, uploadFiles }
  emits('on-success', { response, uploadFile, uploadFiles })
}
const onError = (error: Error, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
  emits('on-error', { error, uploadFile, uploadFiles })
}
const onProgress = (evt: UploadProgressEvent, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
  emits('on-progress', { evt, uploadFile, uploadFiles })
}
const onChange = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
  emits('on-change', { uploadFile, uploadFiles })
}
const onExceed = (files: File[], uploadFiles: UploadFiles) => {
  emits('on-exceed', { files, uploadFiles })
}
const beforeUpload = (rawFile: UploadRawFile) => { emits('before-upload', rawFile) }

const beforeRemove = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
  emits('before-remove', { uploadFile, uploadFiles })
}
onMounted(() => {
  initFrom()
})
watch(() => props.options, () => {
  initFrom()
}, { deep: true })
//派发方法或者属性
defineExpose({
  resetFields,
  formValidate,
  getFormData
})
</script>
<style lang='less' scoped>
</style>